#include "Expand/EventManager.h"
#include "Log.h"
#include "GameSingleton.h"

namespace PocketSurvival
{
    EventManager::EventManager()
    {
        const std::type_info &IInventoryEventInfo = typeid(IInventoryEvent);
        m_eventMap[IInventoryEventInfo.hash_code()] = std::vector<IEvent *>();
        inventoryEvent = new InventoryEvent(m_eventMap[IInventoryEventInfo.hash_code()]);


        const std::type_info &ISignEventInfo = typeid(ISignEvent);
        m_eventMap[ISignEventInfo.hash_code()] = std::vector<IEvent *>();
        signEvent = new SignEvent(m_eventMap[ISignEventInfo.hash_code()]);


        const std::type_info &IInventoryOpenEventInfo = typeid(IInventoryOpenEvent);
        m_eventMap[IInventoryOpenEventInfo.hash_code()] = std::vector<IEvent *>();
        inventoryOpenEvent = new InventoryOpenEvent(m_eventMap[IInventoryOpenEventInfo.hash_code()]);


        const std::type_info &IPlayerEventInfo = typeid(IPlayerEvent);
        m_eventMap[IPlayerEventInfo.hash_code()] = std::vector<IEvent *>();
        playerEvent = new PlayerEvent(m_eventMap[IPlayerEventInfo.hash_code()]);


        const std::type_info &ICreatureEventInfo = typeid(ICreatureEvent);
        m_eventMap[ICreatureEventInfo.hash_code()] = std::vector<IEvent *>();
        creatureEvent = new CreatureEvent(m_eventMap[ICreatureEventInfo.hash_code()]);
    }

    EventManager::~EventManager()
    {
        delete inventoryEvent;
        delete signEvent;
        delete inventoryOpenEvent;
        delete playerEvent;
        delete creatureEvent;
    }

    
    // IInventoryEvent
    bool InventoryEvent::playerDrop(ComponentPlayer *componentPlayer)
    {
        bool result = true;
        for(IEvent *event : m_eventVec)
        {
            if(false == static_cast<IInventoryEvent*>(event)->playerDrop(componentPlayer))
            {
                result = false;
            }
        }
        return result;
    }
    bool InventoryEvent::playerDrapDrop(ComponentPlayer *componentPlayer, const Vector3 &dropVelocity, IInventory *inventory, uint32_t slotIndex, uint32_t count)
    {
        bool result = true;
        for(IEvent *event : m_eventVec)
        {
            if(false == static_cast<IInventoryEvent*>(event)->playerDrapDrop(componentPlayer, dropVelocity, inventory, slotIndex, count))
            {
                result = false;
            }
        }
        return result;
    }
    bool InventoryEvent::playerHandleMoveItem(std::shared_ptr<PlayerData> playerData, IInventory *sourceInventory, uint32_t sourceSlotIndex, IInventory *targetInventory, int32_t targetSlotIndex, uint32_t count)
    {
        bool result = true;
        for(IEvent *event : m_eventVec)
        {
            if(false == static_cast<IInventoryEvent*>(event)->playerHandleMoveItem(playerData, sourceInventory, sourceSlotIndex, targetInventory, targetSlotIndex, count))
            {
                result = false;
            }
        }
        return result;
    }
    bool InventoryEvent::playerHandleDragDrop(std::shared_ptr<PlayerData> playerData, IInventory *sourceInventory, uint32_t sourceSlotIndex, DragMode dragMode, IInventory *targetInventory, uint32_t targetSlotIndex, bool processingOnly)
    {
        bool result = true;
        for(IEvent *event : m_eventVec)
        {
            if(false == static_cast<IInventoryEvent*>(event)->playerHandleDragDrop(playerData, sourceInventory, sourceSlotIndex, dragMode, targetInventory, targetSlotIndex, processingOnly))
            {
                result = false;
            }
        }
        return result;
    }




    // ISignEvent
    bool SignEvent::playerTouchSign(std::shared_ptr<PlayerData> playerData, const Point3 &point)
    {
        bool result = true;
        for(IEvent *event : m_eventVec)
        {
            if(false == static_cast<ISignEvent*>(event)->playerTouchSign(playerData, point))
            {
                result = false;
            }
        }
        return result;
    }
    bool SignEvent::playerEditSign(std::shared_ptr<PlayerData> playerData, SignTextData &signTextData)
    {
        bool result = true;
        for(IEvent *event : m_eventVec)
        {
            if(false == static_cast<ISignEvent*>(event)->playerEditSign(playerData, signTextData))
            {
                result = false;
            }
        }
        return result;
    }




    // IInventoryOpenEvent
    bool InventoryOpenEvent::openInventory(std::shared_ptr<PlayerData> playerData, IInventory *inventory)
    {
        bool result = true;
        for(IEvent *event : m_eventVec)
        {
            if(false == static_cast<IInventoryOpenEvent*>(event)->openInventory(playerData, inventory))
            {
                result = false;
            }
        }
        return result;
    }
    bool InventoryOpenEvent::openPointInventory(std::shared_ptr<PlayerData> playerData, const Point3 &point, IInventory *inventory)
    {
        bool result = true;
        for(IEvent *event : m_eventVec)
        {
            if(false == static_cast<IInventoryOpenEvent*>(event)->openPointInventory(playerData, point, inventory))
            {
                result = false;
            }
        }
        return result;
    }




    // IPlayerEvent
    bool PlayerEvent::cmdFrontMessage(std::shared_ptr<PlayerData> playerData, std::string &message, std::vector<uint8_t> &toClients)
    {
        bool result = true;
        for(IEvent *event : m_eventVec)
        {
            if(false == static_cast<PlayerEvent*>(event)->cmdFrontMessage(playerData, message, toClients))
            {
                result = false;
            }
        }
        return result;
    }
    bool PlayerEvent::message(std::shared_ptr<PlayerData> playerData, std::string &message, std::vector<uint8_t> &toClients)
    {
        bool result = true;
        for(IEvent *event : m_eventVec)
        {
            if(false == static_cast<PlayerEvent*>(event)->message(playerData, message, toClients))
            {
                result = false;
            }
        }
        return result;
    }
    bool PlayerEvent::playerMove(std::shared_ptr<PlayerData> playerData, const Vector3 &position)
    {
        bool result = true;
        for(IEvent *event : m_eventVec)
        {
            if(false == static_cast<PlayerEvent*>(event)->playerMove(playerData, position))
            {
                result = false;
            }
        }
        return result;
    }
    bool PlayerEvent::playerPlaceBlock(ComponentPlayer *componentPlayer, const Point3 &point, int32_t placeBlockValue)
    {
        bool result = true;
        for(IEvent *event : m_eventVec)
        {
            if(false == static_cast<PlayerEvent*>(event)->playerPlaceBlock(componentPlayer, point, placeBlockValue))
            {
                result = false;
            }
        }
        return result;
    }
    bool PlayerEvent::playerBreakBlock(ComponentPlayer *componentPlayer, const Point3 &point, int32_t digBlockValue, int32_t toolLevel)
    {
        bool result = true;
        for(IEvent *event : m_eventVec)
        {
            if(false == static_cast<PlayerEvent*>(event)->playerBreakBlock(componentPlayer, point, digBlockValue, toolLevel))
            {
                result = false;
            }
        }
        return result;
    }
    void PlayerEvent::playerRestart(ComponentPlayer* componentPlayer)
    {
        for(IEvent *event : m_eventVec)
        {
            static_cast<PlayerEvent*>(event)->playerRestart(componentPlayer);
        }
    }
    bool PlayerEvent::onUse(ComponentMiner *componentMiner, const Ray3& ray)
    {
        bool result = true;
        for(IEvent *event : m_eventVec)
        {
            if(false == static_cast<PlayerEvent*>(event)->onUse(componentMiner, ray))
            {
                result = false;
            }
        }
        return result;
    }
    bool PlayerEvent::onAim(ComponentMiner *componentMiner, const Ray3& ray, AimState state)
    {
        bool result = true;
        for(IEvent *event : m_eventVec)
        {
            if(false == static_cast<PlayerEvent*>(event)->onAim(componentMiner, ray, state))
            {
                result = false;
            }
        }
        return result;
    }





    // CreatureEvent
    bool CreatureEvent::hitBody(ComponentAttacker* attacker, ComponentBody *body, const Vector3 &hitPosition, const Vector3 &hitDirection)
    {
        bool result = true;
        for(IEvent *event : m_eventVec)
        {
            if(false == static_cast<CreatureEvent*>(event)->hitBody(attacker, body, hitPosition, hitDirection))
            {
                result = false;
            }
        }
        return result;
    }
    bool CreatureEvent::injureEntity(ComponentHealth *health, float amount, entt::entity attackerEntity, bool realInjure, const std::string &cause, InjureType injureType)
    {
        bool result = true;
        for(IEvent *event : m_eventVec)
        {
            if(false == static_cast<CreatureEvent*>(event)->injureEntity(health, amount, attackerEntity, realInjure, cause, injureType))
            {
                result = false;
            }
        }
        return result;
    }
    bool CreatureEvent::entityDeath(ComponentHealth *health, float amount, entt::entity attackerEntity, const std::string &cause)
    {
        bool result = true;
        for(IEvent *event : m_eventVec)
        {
            if(false == static_cast<CreatureEvent*>(event)->entityDeath(health, amount, attackerEntity, cause))
            {
                result = false;
            }
        }
        return result;
    }
    bool CreatureEvent::dropAllItems(entt::entity entity)
    {
        bool result = true;
        for(IEvent *event : m_eventVec)
        {
            if(false == static_cast<CreatureEvent*>(event)->dropAllItems(entity))
            {
                result = false;
            }
        }
        return result;
    }
    void CreatureEvent::realTimePosition(ComponentBody *body)
    {
        for(IEvent *event : m_eventVec)
        {
            static_cast<CreatureEvent*>(event)->realTimePosition(body);
        }
    }


} // namespace PocketSurvival
